package main

import (
	"encoding/json"
	"fmt"
	"io"
	"os/exec"
)

// 调试器
type NceDebugger struct {
	binPath string   // 二进制
	binArgs []string // 参数
	stdin   io.WriteCloser
	stdout  io.ReadCloser
	stderr  io.ReadCloser
	chQuit  chan error   // 退出信号
	chRecv  chan Message // 接受应答信号

	isStart bool // 启动
	IsExit  bool // 退出标记
}
type Message struct {
	Len  int    // 数据长度
	Data string // 数据
}
type DebuggerMessage struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func New() *NceDebugger {
	d := &NceDebugger{
		binPath: "../03-ncpk-nvm/nvm",
		chQuit:  make(chan error, 1),
		chRecv:  make(chan Message, 1),
	}

	return d
}

func (s *NceDebugger) SetArgs(args []string) {
	binArgs := []string{
		"-debug",
		"true",
	}
	binArgs = append(binArgs, args...)
	s.binArgs = binArgs
	return
}

func (s *NceDebugger) Run() (err error) {
	go s.Loop(s.chQuit, s.chRecv)

	<-s.chRecv
	s.isStart = true
	// fmt.Println("--> 收到第一条消息")
	return
}

func (s *NceDebugger) Loop(chQuit chan error, chRecv chan Message) {
	// 进程绑定输入和输出到管道
	binPath := s.binPath
	binArgs := s.binArgs
	// fmt.Printf("debugger, %v, %v\n", binPath, binArgs)
	process := exec.Command(binPath, binArgs...)

	stdin, err := process.StdinPipe()
	if err != nil {
		s.chQuit <- err
		return
	}
	stdout, err := process.StdoutPipe()
	if err != nil {
		s.chQuit <- err
		return
	}
	stderr, err := process.StderrPipe()
	if err != nil {
		s.chQuit <- err
		return
	}

	s.stdin = stdin
	s.stdout = stdout
	s.stderr = stderr

	// 错误输出
	go func(ch chan error) {
		for {
			bytBuf := make([]byte, 1024)
			n, err_read := stderr.Read(bytBuf)
			if err_read != nil {
				if err_read == io.EOF {
					fmt.Printf("[stderr] eof, n=%v\n", n)
					s.chQuit <- err_read
					return
				} else {
					s.chQuit <- err_read
					return
				}
			}
			fmt.Printf("[stderr] n=%v, recv:\n%v", n, string(bytBuf))
		}
	}(chQuit)

	// 标准输出
	go func(ch chan error, chRecv chan Message) {
		for {
			//fmt.Println("--> recv, wait")
			bytBuf := make([]byte, 1024)
			n, err_read := stdout.Read(bytBuf)
			if err_read != nil {
				s.chQuit <- err_read
				return
			}
			fmt.Printf("[stdout] n=%v, recv:\n%v", n, string(bytBuf))

			debuggerMsg := DebuggerMessage{}
			errJson := json.Unmarshal(bytBuf[:n], &debuggerMsg)
			if errJson != nil {
				panic(errJson)
			}

			if s.isStart {
				if debuggerMsg.Code == 200 {
					//fmt.Println("---，继续接受")
					continue
				}
			}

			s.chRecv <- Message{
				Len:  n,
				Data: string(bytBuf),
			}
			//		fmt.Println("--> 接受成功后，发送通知")
		}
	}(chQuit, chRecv)
	err = process.Start()
	if err != nil {
		s.chQuit <- err
		return
	}
	//fmt.Println("--> run, end")

	<-s.chQuit
	s.IsExit = true
	fmt.Println("---> Loop 收到退出信号", s.IsExit)
	return
}

// 发送调试指令
func (s *NceDebugger) Send(in string) (out string, err error) {
	stdin := s.stdin
	sw := in + "\n" // 调试指令
	bytWrite := []byte(sw)
	s.chRecv = make(chan Message, 1)
	nw, err_write := stdin.Write(bytWrite)
	if err_write != nil {
		s.chQuit <- err_write
		err = err_write
		fmt.Println("... exit")
		return
	}
	fmt.Printf("[stdin] n=%v, send: %v\n", nw, in)
	//fmt.Println("send方法，等待调试消息的应答")
	//	recvMsg := <-s.chRecv

	select {
	case errQuit := <-s.chQuit:
		err = errQuit
	case recvMsg := <-s.chRecv:
		out = recvMsg.Data
	}

	// fmt.Printf("out1: %+v", recvMsg)
	//recvMsg = <-s.chRecv
	//fmt.Printf("out2: %+v", recvMsg)
	return
}
